﻿using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Threading.Tasks;
using DeepZoomPivotConstructor.VisualLib;
using RenderEngineInterfaces;

namespace SimpleFileRendering
{
    /// <summary>
    /// Given a string that is actually an existing file, attempt to render
    /// the existing file.
    /// </summary>
    [Export(typeof(IRenderItem))]
    [RenderInfo(typeof(string))]
    public class StringToFileInfoRender : IRenderItem, IRenderableObjectCompare
    {

        /// <summary>
        /// So we can do a render or two...
        /// </summary>
        [Import(typeof(IRenderEngine))]
        private IRenderEngine RenderMe { get; set; }

        /// <summary>
        /// Do the rendering - we actually just create a file info and then get
        /// someone to try to render that. The "new" operator is fast enough that
        /// we don't need to take a hit on the effort of creating a task.
        /// [We also know the path exists as a file on the OS as we've checked
        /// it below - if that changes out from under us... well... :-)]
        /// </summary>
        /// <param name="what"></param>
        /// <returns></returns>
        public Task<Visual> Render(object what)
        {
            return RenderMe.RenderToFuture(BuildFilePath(what as string));
        }

        /// <summary>
        /// The actual value for a relative mapping.
        /// </summary>
#pragma warning disable 0649
        [Import("RelativePathBase", AllowDefault = true)]
        private DirectoryInfo RelativePathBase;
#pragma warning restore 0649

        /// <summary>
        /// If this what is a string that is a valid path pointing to a real file, then
        /// we can go for it! But only generically. :-)
        /// </summary>
        /// <param name="what"></param>
        /// <returns></returns>
        public RenderPluginPriority RenderPriority(object what)
        {
            try
            {
                if (BuildFilePath(what as string).Exists)
                {
                    return RenderPluginPriority.RPPGeneric;
                }
            }
            catch
            {
            }
            return RenderPluginPriority.RPPCantDoIt;
        }

        /// <summary>
        /// Build a file path from the basics we've been given.
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private FileInfo BuildFilePath(string path)
        {
            string fullPath = path;
            if (IsRelative(path))
            {
                if (RelativePathBase == null)
                    throw new InvalidOperationException("Unable to resolve a relative path w/out a relative path base");

                fullPath = string.Format(@"{0}\{1}", RelativePathBase.FullName, path);
            }

            return new FileInfo(fullPath);
        }

        /// <summary>
        /// Returns the has of the string, which is really a file.
        /// </summary>
        /// <param name="what"></param>
        /// <returns></returns>
        public long GetObjectHash(object what)
        {
            return (what as string).GetHashCode();
        }

        /// <summary>
        /// See if these guys are equal or  not
        /// </summary>
        /// <param name="o1"></param>
        /// <param name="o2"></param>
        /// <returns></returns>
        public bool ObjectsEqual(object o1, object o2)
        {
            return (o1 as string) == (o2 as string);
        }

        /// <summary>
        /// See if the object is out of date or not by comparing a date.
        /// </summary>
        /// <param name="what"></param>
        /// <param name="metaData"></param>
        /// <returns></returns>
        public bool IsOutOfDate(object what, object metaData)
        {
            var f = new FileInfo(what as string);
            if (!f.Exists)
                return true; // This is bad!!

            var d = (DateTime)metaData;
            return f.LastWriteTime > d;
        }

        /// <summary>
        /// Return the meta data.
        /// </summary>
        /// <param name="what"></param>
        /// <returns></returns>
        public object GetObjectDateMetaData(object what)
        {
            return File.GetLastWriteTime(what as string);
        }

        /// <summary>
        /// See if the path given is relative or not.
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private static bool IsRelative(string p)
        {
            if (p.StartsWith("\\"))
                return false;

            if (p.Contains(":"))
                return false;

            return true;
        }
    }
}
